#ifndef _THINTERNAL_H
#define _THINTERNAL_H

#include "types.hpp"
#include "StartOS.hpp"

#pragma pack(push, 1)

// Starting at offset 36 into the BPB, this is the structure for a FAT12/16 FS
typedef struct struct_BPBFAT1216_struct {
  uint8_t BS_DriveNumber;        // 1
  uint8_t BS_Reserved1;          // 1
  uint8_t BS_BootSig;            // 1
  uint32_t BS_VolumeID;          // 4
  uint8_t BS_VolumeLabel[11];    // 11
  uint8_t BS_FileSystemType[8];  // 8
} BPB1216_struct;

// Starting at offset 36 into the BPB, this is the structure for a FAT32 FS
typedef struct struct_BPBFAT32_struct {
  uint32_t FATSize;              // 4
  uint16_t ExtFlags;             // 2
  uint16_t FSVersion;            // 2
  uint32_t RootCluster;          // 4
  uint16_t FSInfo;               // 2
  uint16_t BkBootSec;            // 2
  uint8_t Reserved[12];          // 12
  uint8_t BS_DriveNumber;        // 1
  uint8_t BS_Reserved1;          // 1
  uint8_t BS_BootSig;            // 1
  uint32_t BS_VolumeID;          // 4
  uint8_t BS_VolumeLabel[11];    // 11
  uint8_t BS_FileSystemType[8];  // 8
} BPB32_struct;

typedef struct struct_BPB_struct {
  uint8_t BS_JumpBoot[3];        // 3
  uint8_t BS_OEMName[8];         // 8
  uint16_t BytesPerSector;       // 2
  uint8_t SectorsPerCluster;     // 1
  uint16_t ReservedSectorCount;  // 2
  uint8_t NumFATs;               // 1
  uint16_t RootEntryCount;       // 2
  uint16_t TotalSectors16;       // 2
  uint8_t Media;                 // 1
  uint16_t FATSize16;            // 2
  uint16_t SectorsPerTrack;      // 2
  uint16_t NumberOfHeads;        // 2
  uint32_t HiddenSectors;        // 4
  uint32_t TotalSectors32;       // 4
  union {
    BPB1216_struct fat16;
    BPB32_struct fat32;
  } FSTypeSpecificData;
} BPB_struct;

typedef struct struct_FatFile83 {
  char filename[8];
  char extension[3];
  uint8_t attributes;
  uint8_t reserved;
  uint8_t creationTimeMs;
  uint16_t creationTime;
  uint16_t creationDate;
  uint16_t lastAccessTime;
  uint16_t eaIndex;
  uint16_t modifiedTime;
  uint16_t modifiedDate;
  uint16_t firstCluster;
  uint32_t fileSize;
} FatFile83;

typedef struct struct_FatFileLFN {
  uint8_t sequence_number;
  uint16_t name1[5];      // 5 Chars of name (UTF 16???)
  uint8_t attributes;     // Always 0x0f
  uint8_t reserved;       // Always 0x00
  uint8_t checksum;       // Checksum of DOS Filename.  See Docs.
  uint16_t name2[6];      // 6 More chars of name (UTF-16)
  uint16_t firstCluster;  // Always 0x0000
  uint16_t name3[2];
} FatFileLFN;

typedef union struct_FatFileEntry {
  FatFile83 msdos;
  FatFileLFN lfn;
} FatFileEntry;

#pragma pack(pop)

// "Legacy" functions
uint32_t fat_size(BPB_struct *bpb);
int total_sectors(BPB_struct *bpb);
int root_dir_sectors(BPB_struct *bpb);
int cluster_count(BPB_struct *bpb);
int fat_type(BPB_struct *bpb);
int first_data_sector(BPB_struct *bpb);
int first_sector_of_cluster(BPB_struct *bpb, int N);
int data_sectors(BPB_struct *bpb);
int fat_sector_number(BPB_struct *bpb, int N);
int fat_entry_offset(BPB_struct *bpb, int N);
int fat_entry_for_cluster(BPB_struct *bpb, uint8_t *buffer, int N);

#endif
